using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static WaterCylinder;


public enum EntityType
{
    /// <summary>
    /// 玩家
    /// </summary>
    Player,
    /// <summary>
    /// 敌人
    /// </summary>
    Enemy,
    /// <summary>
    /// 投射物
    /// </summary>
    Bullet,
    /// <summary>
    /// 实体方块
    /// </summary>
    Block
}

/// <summary>
/// 实体标签
/// </summary>
public enum EntityTag
{
    None,
    /// <summary>
    /// 显示武器图像
    /// </summary>
    WeaponDisplay,
    /// <summary>
    /// 子弹
    /// </summary>
    Bullet
}

/// <summary>
/// <para>实体类是该模板工程中最核心的类，玩家、敌人、子弹等具有RPG属性的实体将继承该类。</para>
/// <para>实体类提供RPG数值的计算、伤害计算、碰撞事件代理的功能。</para>
/// </summary>
public abstract class Entity : MonoBehaviour
{   
    
    #region 实体属性
    
    
    /// <summary>
    /// 协程
    /// </summary>
    protected Coroutine _process;
    
    /// <summary>
    /// 实体类型
    /// </summary>
    public EntityType type;
    
    /// <summary>
    /// 实体速度
    /// </summary>
    public float speed;
    [Tooltip("Disable")]
    [SerializeField]
    private float runtimeSpeed;
    /// <summary>
    /// 朝向
    /// </summary>
    public Vector2 toward;
    
    //RPG数值
    [Tooltip("Bullet|Block")]//使用Tooltip标记的属性不会在对应的EntityType的属性面板中显示，使用|分割
    public float HP;
    [Tooltip("Bullet|Block")]
    public Value maxHP = new Value(100);//最大生命值
    /// <summary>
    /// 受伤间隔
    /// </summary>
    [Tooltip("Bullet|Block")]
    public Value interval = new Value(0);//受伤间隔
    /// <summary>
    /// 受伤时间，受伤时间<interval则说明在受伤间隔中
    /// </summary>
    [Tooltip("Bullet|Block|Disable")]
    public float injuryTime = 0;//受伤时间
    /// <summary>
    /// 基础RPG属性
    /// </summary>
    [Tooltip("Bullet|Block")]
    public RPGValue baseAttribute = new RPGValue(DamageType.None);

    /// <summary>
    /// 武器位置
    /// </summary>
    [SerializeField]
    [Tooltip("Bullet|Block")]
    private Vector2 _weaponPos = Vector2.zero;
    public Vector2 weaponPos{
        get{
            Vector2 pos = transform.position;
            return pos + _weaponPos;
        }
    }
    /// <summary>
    /// 丢弃位置
    /// </summary>
    [SerializeField]
    [Tooltip("Bullet|Block")]
    private Vector2 _dropPos = Vector2.zero;
    public Vector2 dropPos{
        get{
            Vector2 pos = transform.position;
            return pos + _dropPos;
        }
    }
    
    #endregion
    
    #region 列表
    
    //e.g. attributes[Convert.ToInt32(Damage.Magic)]获取魔法伤害相关的属性（RPGValue对象）
    /// <summary>
    /// 属性列表，基于伤害类型分类
    /// </summary>
    [Tooltip("Bullet|Block")]
    public List<RPGValue> attributeList = AllRPGValue();
    private static List<RPGValue> AllRPGValue(){
        List<RPGValue> list = new List<RPGValue>();
        foreach(DamageType t in Enum.GetValues(typeof(DamageType))){
            list.Add(new RPGValue(t));
        }
        return list;
    }
    /// <summary>
    /// 效果列表
    /// </summary>
    [Tooltip("Bullet|Block")]
    public List<Effect> effects = new List<Effect>();
    /// <summary>
    /// 添加效果，保证相同ID的不可重复效果不重复，同步
    /// </summary>
    /// <param name="effect"></param>
    public Effect AddEffect(Effect effect){
        lock(effects){
            effects.ForEach(e => {
                if(e.id == effect.id && !e.canRepeat){
                    if(effect.canFlash){
                        e.End();
                    }else return;
                }
            });
            effects.Add(effect);
            effect.entity = this;
            effect.Start();
        }
        return effect;
    }
    /// <summary>
    /// 移除效果，同步
    /// </summary>
    /// <param name="effect"></param>
    public Effect RemoveEffect(Effect effect){
        lock(effect)if(effects.Contains(effect)){
            effects.Remove(effect);
            return effect;
        }else{
            return null;
        }
        
        
    }
    /// <summary>
    /// 实体标签
    /// </summary>
    public List<EntityTag> tags = new List<EntityTag>{EntityTag.None};
    public bool TagCheck(EntityTag t){
        return tags.Contains(t);
    }    


    #endregion
    
    #region 虚拟方法
    
    /// <summary>
    /// 初始化
    /// </summary>
    protected virtual void OnStart(){}
    /// <summary>
    /// 初始化
    /// </summary>
    protected virtual void Init(){}
    /// <summary>
    /// 协程方法
    /// </summary>
    protected virtual void OnProcess(){}
    /// <summary>
    /// 检测更新输入
    /// </summary>
    protected virtual void OnUpdate(){}
    /// <summary>
    /// 实体碰撞Enter
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityCollisionEnter(Entity other){}
    /// <summary>
    /// 实体碰撞Stay
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityCollision(Entity other){}
    /// <summary>
    /// 实体碰撞Exit
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityCollisionExit(Entity other){}
    /// <summary>
    /// 实体侦测器Enter
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityTriggerEnter(Entity other){}
    /// <summary>
    /// 实体侦测器Stay
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityTrigger(Entity other){}
    /// <summary>
    /// 实体侦测器Exit
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnEntityTriggerExit(Entity other){}
    /// <summary>
    /// 其他碰撞Enter
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherCollisionEnter(Collision2D other){}
    /// <summary>
    /// 其他碰撞Stay
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherCollision(Collision2D other){}
    /// <summary>
    /// 其他碰撞Exit
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherCollisionExit(Collision2D other){}
    /// <summary>
    /// 其他侦测器Enter
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherTriggerEnter(Collider2D other){}
    /// <summary>
    /// 其他侦测器Stay
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherTrigger(Collider2D other){}
    /// <summary>
    /// 其他侦测器Exit
    /// </summary>
    /// <param name="other"></param>
    protected virtual void OnOtherTriggerExit(Collider2D other){}
    /// <summary>
    /// 伤害计算时
    /// </summary>
    /// <param name="source"></param>
    protected virtual void OnDamage(Entity source, Damage damage){}
    /// <summary>
    /// 死亡时
    /// </summary>
    protected virtual void OnDead(Entity other){}

    #endregion
    
    #region 内建方法

    /// <summary>
    /// 改变朝向和速度
    /// </summary>
    /// <param name="toward"></param>
    /// <param name="speed"></param>
    protected void Move(Vector2 toward, float speed){
        this.toward = toward;
        this.speed = speed;
        this.runtimeSpeed = speed;
    }
    protected void SmoothMove(Vector2 toward, float speed = 1, float smoothRate = 1f){
        toward = toward.normalized*speed;
        this.toward = this.toward+(toward-this.toward)*smoothRate*processTime;
        if(this.toward.magnitude < processTime && toward.magnitude < processTime){
            this.toward = Vector2.zero;
        }
        this.runtimeSpeed = this.toward.magnitude;
    }
    /// <summary>
    /// 转向到朝向
    /// </summary>
    protected void Turn(){
        transform.localEulerAngles = new Vector3(0, 0, Angle(Vector2.right, toward));
    }
    /// <summary>
    /// 获取到鼠标位置的向量
    /// </summary>
    /// <returns></returns>
    protected Vector2 ToMouse(){
        Vector2 pos = transform.position;
        return GetMousePosition2D() - pos;
    }
    
    #endregion
    
    #region 外置方法
    
    /// <summary>
    /// 伤害计算
    /// </summary>
    /// <param name="damage"></param>
    /// <param name="source"></param>
    public void ToDamage(Damage damage, Entity other){
        if(injuryTime >= interval.value){
            injuryTime = 0;//重置受伤时间
            damage = Damage.Calculate(damage, baseAttribute);
            damage = Damage.Calculate(damage, attributeList[(int)damage.type]);
            damage = Damage.Calculate(damage, attributeList[(int)damage.etype]);
            damage = Damage.Calculate(damage, attributeList[(int)damage.stype]);
            float d = damage.value;
            OnDamage(other, damage);
            SmallText.CreatSmallText(""+d, transform.position);
            HP -= d;
            if(HP < 0){
                Die(other);
            }
        }
    }
    /// <summary>
    /// 获取某一类型的伤害值
    /// </summary>
    /// <param name="type"></param>
    /// <param name="offset"></param>
    /// <returns></returns>
    public float GetDamage(DamageType type, float offset){
        return attributeList[(int)type].GetDamage(offset);
    }
    /// <summary>
    /// 获取各类型暴击计算后的伤害
    /// </summary>
    /// <param name="source"></param>
    /// <returns></returns>
    public float GetDamage(Damage source){
        RPGValue v = baseAttribute
            + ((source.type == DamageType.None) ? RPGValue.NaN : attributeList[(int)source.type])
            + ((source.etype == DamageType.None) ? RPGValue.NaN : attributeList[(int)source.etype])
            + ((source.stype == DamageType.None) ? RPGValue.NaN : attributeList[(int)source.stype]);
        return v.GetDamage(source.value);
    }
    /// <summary>
    /// 死亡
    /// </summary>
    /// <param name="source"></param>
    public void Die(Entity other){
        OnDead(other);
        StopCoroutine(_process);
        Delete(gameObject);//销毁实体
    }
    
    #endregion
    
    #region Monobehaviour
    
    void Awake(){
        Init();
    }
    void Start(){
        OnStart();
        _process = StartCoroutine(process());
    }
    public void OnCollisionEnter2D(Collision2D other){
        Entity e = other.gameObject.GetComponent<Entity>();
        if(e != null){
            OnEntityCollisionEnter(e);
        }else{
            OnOtherCollisionEnter(other);
        }
    }
    public void OnCollisionStay2D(Collision2D other){
        Entity e = other.gameObject.GetComponent<Entity>();
        if(e != null){
            OnEntityCollision(e);
        }else{
            OnOtherCollision(other);
        }
    }
    public void OnCollisionExit2D(Collision2D other){
        Entity e = other.gameObject.GetComponent<Entity>();
        if(e != null){
            OnEntityCollisionExit(e);
        }else{
            OnOtherCollisionExit(other);
        }
    }
    public void OnTriggerEnter2D(Collider2D other){
        Entity e = other.GetComponent<Entity>();
        if(e != null){
            OnEntityTriggerEnter(e);
        }else{
            OnOtherTriggerEnter(other);
        }
    }
    public void OnTriggerStay2D(Collider2D other){
        Entity e = other.GetComponent<Entity>();
        if(e != null){
            OnEntityTrigger(e);
        }else{
            OnOtherTrigger(other);
        }
    }
    public void OnTriggerExit2D(Collider2D other){
        Entity e = other.GetComponent<Entity>();
        if(e != null){
            OnEntityTriggerExit(e);
        }else{
            OnOtherTriggerExit(other);
        }
    }
    
    void Update(){
        OnUpdate();
        Rigidbody2D r = GetComponent<Rigidbody2D>();
        if(r){
            //移动
            r.velocity = toward.normalized * runtimeSpeed;
        }
    }
    public static float processTime = .05f;
    IEnumerator process(){
        while(true){
            OnProcess();
            //计算受伤间隔
            injuryTime += processTime;
            yield return new WaitForSeconds(processTime);
        }
    }

    #endregion
    
}